#ifndef GZLL_H__
#define GZLL_H__

#include <stdint.h>
#include <stdbool.h>
#include "gazell_params_cfg.h"
#include "hal_nrf.h"

/**
Typical transmit time including auto retry delay and 130 us radio startup.
Used for calculating host mode 1 burst behavior.
*/
#define GZLL_TYP_TX_PERIOD          (130 + ((GZLL_CONST_BYTES_PR_PACKET + GZLL_MAX_FW_PAYLOAD_LENGTH) * GZLL_US_PR_BYTE) + GZLL_AUTO_RETR_DELAY)

/**
Dynamic protocol parameters.
*/
typedef enum {
    GZLL_PARAM_DEVICE_MODE,                             /*<设备运行模式,设备共有5种模式*/
    GZLL_PARAM_TX_TIMEOUT,                              /*<TX重发重发次数，如果设为0，则取决于TX_Attempts*/
    GZLL_PARAM_TX_ATTEMPTS_PR_CHANNEL_WHEN_SYNC_ON,     /*<当同步后，切换频道次数*/
    GZLL_PARAM_TX_ATTEMPTS_PR_CHANNEL_WHEN_SYNC_OFF,    /*<不同步，切换频道次数*/
    GZLL_PARAM_HOST_MODE,                               /*<主机运行模式*/
    GZLL_PARAM_RX_PIPES,                                /*<接收通道，监听通道*/
    GZLL_PARAM_RX_TIMEOUT,                              /*<接收超时时间*/
    GZLL_PARAM_HOST_MODE_1_CYCLE_PERIOD,                /*<主机在模式1低功耗处理的周期*/
    GZLL_PARAM_RX_PERIOD,                               /*<接收周期ms*/
    GZLL_PARAM_RX_PERIOD_MODIFIER,                      /*<用来校准同步计时器*/
    GZLL_PARAM_RX_CHANNEL_HOLD_PERIODS,                 /*<主机接收时隙*/
    GZLL_PARAM_CRYPT_PIPES,                             /*<加密通道*/
    GZLL_PARAM_OUTPUT_POWER,                            /*<输出功率*/
    GZLL_PARAM_POWER_DOWN_IDLE_ENABLE,                  /*<电源关机进入idle状态*/
    GZLL_PARAM_MAX_SYNC_PERIOD,                         /*<最大同步周期*/
    GZLL_PARAM_COLLISION_CHANNEL_SWITCH_LIMIT,          /*<每个频道发送的最大次数，超过就进行切换频道*/
    GZLL_DYN_PARAM_SIZE
} gzll_dyn_params_t;

/**
Protocol states.
*/
typedef enum {
    GZLL_IDLE,            /*<空闲状态*/
    GZLL_DEVICE_ACTIVE,   /*<设备激活状态*/
    GZLL_HOST_ACTIVE      /*<主机激活状态*/
} gzll_states_t;

/**
RX (host) modes.
*/
typedef enum {
    GZLL_HOST_MODE_0,     /*<主机低延时模式*/
    GZLL_HOST_MODE_1,     /*<主机低功耗模式*/
} gzll_rx_modes_t;

/**
TX (device) modes.
*/
typedef enum {
    GZLL_DEVICE_MODE_0,   /*<异步模式，频率捷变*/
    GZLL_DEVICE_MODE_1,   /*<异步模式，跳频*/
    GZLL_DEVICE_MODE_2,   /*<半同步模式，频率捷变*/
    GZLL_DEVICE_MODE_3,   /*<半同步模式，跳频*/
    GZLL_DEVICE_MODE_4,   /*<半同步模式，低延时跳频*/
} gzll_device_modes_t;

/**
daterate
*/
#define GZLL_DR_1MBPS       0
#define GZLL_DR_2MBPS       1
#define GZLL_DR_250KBPS     2

/*
CRC length.

Possible values:
@arg HAL_NRF_CRC_8BIT
@arg HAL_NRF_CRC_16BIT
*/
#define GZLL_CRC                    HAL_NRF_CRC_16BIT

/*
Address width to be used by Gazell.
*/
#define GZLL_ADDRESS_WIDTH          HAL_NRF_AW_5BYTES

/*
Number of bytes pEr packet exclusive the payload.
That is: 1 preamble + 2 CRC + 5 address + ~1 byte packet control
*/
#define GZLL_CONST_BYTES_PR_PACKET  (1 + 2 + 5 + 1)

// ==================================================================
/// @brief  : 初始化Gazell协议，这个必须被调用
// ==================================================================
void gzll_init(void);

// ==================================================================
/// @brief  : 用于设置管道的地址，只能在GZLL_IDLE状态才能更改
///
/// @param  : pipe 指定pipe
/// @param  : address 设定地址
// ==================================================================
void gzll_set_address(hal_nrf_address_t pipe, const uint8_t *address);

// ==================================================================
/// @brief  : 设置跳频频道列表
///
/// @param  : channels 频道列表
/// @param  : size 频道列表长度
// ==================================================================
void gzll_set_channels(uint8_t *channels, uint8_t size);

// ==================================================================
/// @brief  : 用于设置动态协议参数
///
/// @param  : param 指定参数
/// @param  : value 设定值
// ==================================================================
void gzll_set_param(gzll_dyn_params_t param, uint16_t value);

// ==================================================================
/// @brief  : 获取指定参数值
///
/// @param  : param 指定参数
///
/// @returns: 参数的设定值
// ==================================================================
uint16_t gzll_get_param(gzll_dyn_params_t param);

// ==================================================================
/// @brief  : 获取当前状态
///
/// @returns: GZLL_IDLE, GZLL_DEVICE_ACTIVE, GZLL_HOST_ACTIVE
// ==================================================================
gzll_states_t gzll_get_state(void);

// ==================================================================
/// @brief  : 强制进入idle状态
// ==================================================================
void gzll_goto_idle(void);

// ==================================================================
/// @brief  : 检测指定通道接收数据是否就绪
///
/// @param  : pipe 指定通道
///
/// @returns: ture or not
// ==================================================================
bool gzll_rx_data_ready(uint8_t pipe);

// ==================================================================
/// @brief  : 获取已收到数据pipe通道
///
/// @returns: 有pipe有数据，则返回pipe编号，没有数据则返回0xff
// ==================================================================
uint8_t gzll_get_rx_data_ready_pipe_number(void);

// ==================================================================
/// @brief  : 读取接收FIFO数据
///
/// @param  : dst 数据缓存
/// @param  : length 数据长度
/// @param  : pipe 指定通道
///
/// @returns: ture 读出数据，false 没有数据
// ==================================================================
bool gzll_rx_fifo_read(uint8_t *dst, uint8_t *length, uint8_t *pipe);

// ==================================================================
/// @brief  : 检测接收信号质量
///
/// @returns: true if receive signal level >= -64 dBm.
/// @returns: false if receive signal level < -64 dBm.
// ==================================================================
bool gzll_rx_power_high(void);

// ==================================================================
/// @brief  : 获取通道列表大小
// ==================================================================
uint8_t gzll_get_channel_tab_size(void);

// ==================================================================
/// @brief  : 获取通道列表
///
/// @param  : channels 通道缓存
// ==================================================================
void gzll_get_channels(uint8_t *channels);

// ==================================================================
/// @brief  : 获取指定通道地址
///
/// @param  : pipe 指定通道
/// @param  : address 地址缓存
// ==================================================================
void gzll_get_address(uint8_t pipe, uint8_t* address);

// ==================================================================
/// @brief  : 清理发送FIFO区
// ==================================================================
void gzll_tx_fifo_flush(void);

// ==================================================================
/// @brief  : 清理接收FIFO区
// ==================================================================
void gzll_rx_fifo_flush(void);

// ==================================================================
/// @brief  : nrf IRQ中断处理函数，nrf必须要配置为中断模式，用户在配置的中断调用
// ==================================================================
void gzll_radio_isr_function(void);

// ==================================================================
/// @brief  : 定时器处理函数，设备主要管理数据发送和跳频
// ==================================================================
void gzll_timer_isr_function(void);

// ==================================================================
/// @brief  : 设备发送数据,主机不能主动发送数据
///
/// @param  : src 数据包
/// @param  : length 数据包长度
/// @param  : pipe 指定通道
///
/// @returns: 
// ==================================================================
bool gzll_tx_data(const uint8_t *src, uint8_t length, uint8_t pipe);

// ==================================================================
/// @brief  : 检测发送是否成功，只有在IDLE情况下读取才有效
///
/// @returns: ture or not
// ==================================================================
bool gzll_tx_success(void);

// ==================================================================
/// @brief  : 获取tx重发尝试次数
///
/// @returns: 尝试次数
// ==================================================================
uint16_t gzll_get_tx_attempts(void);

// ==================================================================
/// @brief  : 获取tx频道切换次数
///
/// @returns: 切换次数
// ==================================================================
uint16_t gzll_get_tx_channel_switches(void);

// ==================================================================
/// @brief  : 开始接收数据，主机才能调用
// ==================================================================
void gzll_rx_start(void);

// ==================================================================
/// @brief  : 将数据写入到下一个ack包中
///
/// @param  : src 数据包
/// @param  : length 数据包长度
/// @param  : pipe 指定通道
///
/// @returns: true or not
// ==================================================================
bool gzll_ack_payload_write(const uint8_t *src, uint8_t length, uint8_t pipe);

//-----------------------------------------------------------------------------
// Compile time defines
//-----------------------------------------------------------------------------
#define GZLL_MAX_INTERNAL_PAYLOAD_LENGTH                                32      /*<不可以改变*/

#if (GZLL_MAX_FW_PAYLOAD_LENGTH > GZLL_MAX_ACK_PAYLOAD_LENGTH)
    #define GZLL_MAX_PAYLOAD_LENGTH GZLL_MAX_FW_PAYLOAD_LENGTH
#else
    #define GZLL_MAX_PAYLOAD_LENGTH GZLL_MAX_ACK_PAYLOAD_LENGTH
#endif

#if (GZLL_MAX_FW_PAYLOAD_LENGTH > GZLL_MAX_INTERNAL_PAYLOAD_LENGTH)
{
    #error "GZLL_MAX_FW_PAYLOAD_LENGTH is limited to 32"
}
#endif

#if (GZLL_MAX_ACK_PAYLOAD_LENGTH > GZLL_MAX_INTERNAL_PAYLOAD_LENGTH)
{
    #error "GZLL_MAX_ACK_PAYLOAD_LENGTH is limited to 32"
}
#endif

#define GZLL_INTERNAL_FW_PAYLOAD_LENGTH         GZLL_MAX_FW_PAYLOAD_LENGTH
#define GZLL_INTERNAL_ACK_PAYLOAD_LENGTH        GZLL_MAX_ACK_PAYLOAD_LENGTH

#if (GZLL_INTERNAL_FW_PAYLOAD_LENGTH > GZLL_INTERNAL_ACK_PAYLOAD_LENGTH)
    #define GZLL_INTERNAL_PAYLOAD_LENGTH        GZLL_INTERNAL_FW_PAYLOAD_LENGTH
#else
    #define GZLL_INTERNAL_PAYLOAD_LENGTH        GZLL_INTERNAL_ACK_PAYLOAD_LENGTH
#endif

#if (GZLL_DATARATE == GZLL_DR_2MBPS)
    #define GZLL_US_PR_BYTE                     4
    #define GZLL_HAL_DATARATE                   HAL_NRF_2MBPS
    #define GZLL_HOST_CE_LOW_IDLE_DELAY         15 // Host cative -> Idle delay. 9 * 50us = 500 us.
    #if(GZLL_INTERNAL_ACK_PAYLOAD_LENGTH > 15)
        #define GZLL_AUTO_RETR_DELAY            500
    #else
        #define GZLL_AUTO_RETR_DELAY            250
    #endif
#endif

#if (GZLL_DATARATE == GZLL_DR_1MBPS)
    #define GZLL_US_PR_BYTE                     8
    #define GZLL_HAL_DATARATE                   HAL_NRF_1MBPS
    #define GZLL_HOST_CE_LOW_IDLE_DELAY         14 // Host cative -> Idle delay. 13 * 50us = 700 us.
    #if(GZLL_INTERNAL_ACK_PAYLOAD_LENGTH > 5)
        #define GZLL_AUTO_RETR_DELAY            500
    #else
        #define GZLL_AUTO_RETR_DELAY            250
    #endif
#endif

#if (GZLL_DATARATE == GZLL_DR_250KBPS)
    #define GZLL_US_PR_BYTE                     32
    #define GZLL_HAL_DATARATE                   HAL_NRF_250KBPS
    #define GZLL_HOST_CE_LOW_IDLE_DELAY         37 // Host cative -> Idle delay. 36 * 50us = 1850 us.

    #if(GZLL_INTERNAL_ACK_PAYLOAD_LENGTH == 0)
        #define GZLL_AUTO_RETR_DELAY            500
    #elif(GZLL_INTERNAL_ACK_PAYLOAD_LENGTH < 8)
        #define GZLL_AUTO_RETR_DELAY            750
    #elif(GZLL_INTERNAL_ACK_PAYLOAD_LENGTH < 16)
        #define GZLL_AUTO_RETR_DELAY            1000
    #elif(GZLL_INTERNAL_ACK_PAYLOAD_LENGTH < 24)
        #define GZLL_AUTO_RETR_DELAY            1250
    #else
        #define GZLL_AUTO_RETR_DELAY            1500
    #endif
#endif

#endif // GZLL_H__
